home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / BORL_TIP / TI100 / TI152.ASC < prev    next >
Text File  |  1992-09-02  |  22KB  |  661 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  10.   VERSION : All
  11.        OS : PC-DOS, MS-DOS
  12.      DATE : August 1, 1986                              PAGE : 1/10
  13.     TITLE : INTERRUPT HANDLER
  14.  
  15.  
  16.  
  17.  
  18.   The following example routines are public domain programs that
  19.   have been uploaded to our Forum on CompuServe. As a courtesy to
  20.   our users that do not have immediate access to CompuServe,
  21.   Technical Support distributes these routines free of charge.
  22.  
  23.   However, because these routines are public domain programs, not
  24.   developed by Borland International, we are unable to provide any
  25.   technical support or assistance using these routines. If you need
  26.   assistance using these routines, or are experiencing difficu
  27.  
  28.   DumbTerm is an example program written to demonstrate the use of
  29.   both interrupt routines and COM port communication. There are
  30.   some inline instructions that are used in the interrupt routine
  31.   that do not appear in the Turbo Pascal manual. When making you
  32.  
  33.   This program was written by:
  34.  
  35.   Jim McCarthy                and          Andy Batony
  36.     Technical Support                       Teleware Incorporated
  37.     Borland International
  38.   _____________________________________________________________________
  39.   ---------------------------------------------------------------------
  40.  
  41.   PROGRAM dumbterm;
  42.  
  43.     CONST
  44.       hex        : string[16] = '0123456789ABCDEF'; { Constant used to }
  45.                                             { convert decimal to hex   }
  46.       irq4       = $30;                     { Interrupt vector address }
  47.                                             { for COM1.                }
  48.       irq3       = $2C;                     { Vector for COM2.         }
  49.       eoi        = $20;                     {                          }
  50.       com1base   = $03F8;                   { Port address of COM1.    }
  51.       com2base   = $02F8;                   { Port address of COM2.    }
  52.                                             { Offset to add to         }
  53.       intenreg   = 1;                       { com#base for Interrupt   }
  54.                                             { enable register          }
  55.       intidreg   = 2;                       { Interrupt id register    }
  56.       linectrl   = 3;                       { Line control register    }
  57.       modemctrl  = 4;                       { Modem control register   }
  58.       linestat   = 5;                       { Line status register     }
  59.       modemstat  = 6;                       { Modem status register    }
  60.       buffsize   = 1024;                    { Size of the ring buffer  }
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  76.   VERSION : All
  77.        OS : PC-DOS, MS-DOS
  78.      DATE : August 1, 1986                              PAGE : 2/10
  79.     TITLE : INTERRUPT HANDLER
  80.  
  81.  
  82.  
  83.  
  84.     TYPE                                    { Type declarations        }
  85.       str4       = string[4];
  86.       str80      = string[80];
  87.       ratetype   = (rate300,rate1200,rate4800,rate9600);
  88.       comtype    = (com1,com2);
  89.       bytechar   = record case boolean of
  90.                      true :(o:byte);
  91.                      false:(c:char)
  92.                    end;
  93.  
  94.  
  95.       regrec     = record
  96.                      ax,bx,cx,dx,bp,di,si,ds,es,flags : integer;
  97.                    end;
  98.  
  99.     VAR
  100.       segment    : integer absolute cseg:$00A0;  { Address for storing }
  101.       intbuffer  : array [0..buffsize] of bytechar;  { DS Ring buffer  }
  102.       oldvecseg,                       { Segment of DOS set            }
  103.       oldvecoff,                       { Offset of DOS set com int.    }
  104.       head,                            { Index to the head of the      }
  105.                                        { ring buffer.                  }
  106.       tail,                            { Tail index of the ring buff   }
  107.       comport,                         { Comport address               }
  108.       i          : integer;            { Counter                       }
  109.       comp       : comtype;            { Used to specify which comport }
  110.       ch,                              { Temporary character buffer    }
  111.       kch        : char;               { Char keyed in from the key-   }
  112.                                        { board                         }
  113.       temp       : string[80];         { Temporary buffer              }
  114.       tbyte,
  115.       lbyte      : byte;
  116.       showok     : boolean;
  117.       registers  : regrec;             { Registers used in DOS call    }
  118.  
  119.   {--------------------------------------------------------------------
  120.   This is the interrupt handler for the COM1 or COM2 comports. Notice the
  121.   restoration of the DS register through a move to the AX from address
  122.   CS:00A0.  The absolute variable "segment" is initialized at the beginning
  123.   of the program to contain the value of "
  124.   --------------------------------------------------------------------}
  125.    PROCEDURE IntHandler;
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  142.   VERSION : All
  143.        OS : PC-DOS, MS-DOS
  144.      DATE : August 1, 1986                              PAGE : 3/10
  145.     TITLE : INTERRUPT HANDLER
  146.  
  147.  
  148.  
  149.  
  150.       BEGIN
  151.         inline( $50          { push ax       }
  152.                /$53          { push bx       }
  153.                /$51          { push cx       }
  154.                /$52          { push dx       }    { Save all the       }
  155.                /$57          { push di       }    { registers          }
  156.                /$56          { push si       }
  157.                /$06          { push es       }
  158.                /$1E          { push ds       }
  159.                /$2E          { cs:           }
  160.                /$A1 /$A0 /$00{ mov ax, [00A0]}    { Get the Current    }
  161.                /$50          { push ax       }    { data segment       }
  162.                /$1F          { pop ds        } ); { Restore the DS     }
  163.                                                   { register           }
  164.  
  165.         tbyte := port[ comport ];            { Get the char in the port}
  166.         lbyte := port[ comport + linestat ]; { Get status of the port  }
  167.         If ( head < buffsize ) then          { Check bounds of the ring}
  168.           head := head + 1                   { buffer, and if smaller  }
  169.         else                                 { then increment by one   }
  170.           head := 0;                         { otherwise set to the    }
  171.                                              { first element           }
  172.         intbuffer[ head ].o := tbyte;        { Load the buffer w/ the  }
  173.                                              { character               }
  174.         port[$20] := $20;                    { Enable all other        }
  175.                                              { interrupts except the   }
  176.                                              { calling INT ( 0C )      }
  177.         inline( $1F          { pop ds        }
  178.                /$07          { pop es        }
  179.                /$5E          { pop si        }
  180.                /$5F          { pop di        }
  181.                /$5A          { pop dx        }
  182.                /$59          { pop cx        } { Restore all registers }
  183.                /$5B          { pop bx        }
  184.                /$58          { pop ax        }
  185.                /$5D          { pop     bp    } { Reset the stack to its}
  186.                /$89 /$EC     { mov     sp,bp } { proper position       }
  187.                /$5D          { pop     bp    }
  188.                /$CF );       { iret          } { Return                }
  189.       END;
  190.   {---------------------------------------------------------------------
  191.         The procedure AskCom gets the comport to communicate through.
  192.   ---------------------------------------------------------------------}
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  208.   VERSION : All
  209.        OS : PC-DOS, MS-DOS
  210.      DATE : August 1, 1986                              PAGE : 4/10
  211.     TITLE : INTERRUPT HANDLER
  212.  
  213.  
  214.  
  215.  
  216.     PROCEDURE AskCom( var comp : comtype );
  217.  
  218.       VAR
  219.         ch : char;
  220.  
  221.       BEGIN
  222.         write( 'What port is the modem in ( 1 or 2 ) : ' );
  223.                                                 { Write prompt        }
  224.         Repeat
  225.           read( kbd,ch );                       { Get the character   }
  226.         Until ( ch in ['1','2'] );              { and check bounds    }
  227.         If ( ch = '1' ) then
  228.           Begin
  229.             writeln( 'COM1:' );                 { Set to COM1         }
  230.             comp := com1;
  231.           End
  232.         else
  233.           Begin
  234.             writeln( 'COM2:' );
  235.             comp := com2;                       { Set to COM2         }
  236.           End;
  237.       END;
  238.  
  239.   {--------------------------------------------------------------------
  240.   This procedure sets the baud rate of the comport to either 300, 1200, 4800,
  241.   or 9600  baud. The Divisor latches are set according to the table in the
  242.   IBM hardware technical reference manual (p.1-238 ).
  243.   --------------------------------------------------------------------}
  244.  
  245.    PROCEDURE SetRate(r:ratetype);
  246.  
  247.       VAR
  248.         tlcr,                          { Line control register        }
  249.         tdlmsb,                        { Divisor latch MSB            }
  250.         tdllsb    : byte;              { Divisor latch LSB            }
  251.       BEGIN
  252.         tdlmsb:=0;                     { Set DL MSB to 0 for 1200,    }
  253.                                        { 4800 and 9600 baud           }
  254.         case r of                      { Use case to check baud rate  }
  255.           rate300 :  begin             { Check for 300 baud           }
  256.                        tdlmsb:=1;      { Set DL MSB to 01             }
  257.                        tdllsb:=$80;    { Set DL LSB to 80             }
  258.                      end;              { for a total of 0180          }
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  274.   VERSION : All
  275.        OS : PC-DOS, MS-DOS
  276.      DATE : August 1, 1986                              PAGE : 5/10
  277.     TITLE : INTERRUPT HANDLER
  278.  
  279.  
  280.  
  281.  
  282.           rate1200 : tdllsb:=$60;            { 1200 set LSB to 60     }
  283.           rate4800 : tdllsb:=$18;            { 4800 set LSB to 18     }
  284.           rate9600 : tdllsb:=$0c;            { 0C for 9600 baud       }
  285.  
  286.         end;
  287.         tlcr:=port[comport+linectrl];        { Get the Line control   }
  288.                                              { register               }
  289.         port[comport+linectrl]:=tlcr or $80; { Set Divisor Latch      }
  290.                                              { Access Bit in order to }
  291.         port[comport]:=tdllsb;               { access divisor latches,}
  292.                                              { then store the values  }
  293.         port[comport+1]:=tdlmsb;             { for the desired baud   }
  294.                                              { rate                   }
  295.         port[comport+linectrl]:=tlcr and $7f;{ then clear the DLAB    }
  296.                                              { in order to access to  }
  297.                                              { the receiver buffer    }
  298.       END;
  299.  
  300.   {--------------------------------------------------------------------
  301.   WhatRate is the input procedure that uses SetRate to set the correct
  302.   baud rate.
  303.   --------------------------------------------------------------------}
  304.  
  305.     PROCEDURE WhatRate;
  306.  
  307.       BEGIN
  308.         writeln;                           { Display prompt           }
  309.         write('what baud rate ([3]00,[1]200,[4]800,[9]600) ');
  310.         read(kbd,kch);                     { Read in the baud rate    }
  311.   -
  312.         case kch of
  313.           '3':SetRate(rate300);           { Set the corresponding rate }
  314.           '1':SetRate(rate1200);          {             .              }
  315.           '4':SetRate(rate4800);          {             .              }
  316.           '9':SetRate(rate9600);          {             .              }
  317.         end;
  318.         writeln(kch);
  319.       END;
  320.   {--------------------------------------------------------------------
  321.   The procedure IntOn sets up the interrupt handler vectors, and
  322.   communication protocol.
  323.   --------------------------------------------------------------------}
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  340.   VERSION : All
  341.        OS : PC-DOS, MS-DOS
  342.      DATE : August 1, 1986                              PAGE : 6/10
  343.     TITLE : INTERRUPT HANDLER
  344.  
  345.  
  346.  
  347.  
  348.     PROCEDURE IntOn(com:comtype);
  349.  
  350.       CONST
  351.         bits5=0;
  352.         bits6=1;
  353.         bits7=2;
  354.  
  355.  
  356.         bits8=3;
  357.         stopbit1=0;                         { These are constants used }
  358.         stopbit2=4;                         { to define parity, stop   }
  359.         noparity=0;                         { bits, data bits, etc.    }
  360.         parity=8;
  361.         evenparity=16;
  362.         dtrtrue=1;
  363.         rtstrue=2;
  364.         bit3true=8;
  365.  
  366.       VAR
  367.         tbyte   : byte;                     { Temporary byte buffer    }
  368.         i       : integer;                  { counter                  }
  369.  
  370.       BEGIN
  371.         head:=0;                            { Initialize the ring      }
  372.         tail:=0;                            { buffer indexes           }
  373.         case com of
  374.           com1:comport:=com1base;           { Set the com port to      }
  375.                                             { talk to                  }
  376.           com2:comport:=com2base;
  377.         end;
  378.         tbyte := port[ comport ];           { Read the ports to clear  }
  379.         tbyte := port[ comport + linestat ];{ any error conditions     }
  380.         WhatRate;                           { Get the baud rate        }
  381.         port[ comport + linectrl ] := bits7 + stopbit1 + noparity;
  382.                                             { Set the protocall        }
  383.         port[ comport + modemctrl ] := dtrtrue + rtstrue + bit3true;
  384.         port[ comport + intenreg ] := 1;    { Enable com port          }
  385.         tbyte := port[$21];                 { interrupts               }
  386.         with registers do
  387.           begin
  388.             ax:=$2500;                      { Load the function number }
  389.                                             { for redefining an        }
  390.                                             { interrupt                }
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  406.   VERSION : All
  407.        OS : PC-DOS, MS-DOS
  408.      DATE : August 1, 1986                              PAGE : 7/10
  409.     TITLE : INTERRUPT HANDLER
  410.  
  411.  
  412.  
  413.  
  414.             ds:=cseg;                       { Get and set the segment  }
  415.            dx:=ofs(IntHandler);            { and offset of the handler}
  416.           end;
  417.         case com of
  418.           com1: begin
  419.                   oldvecoff:=memw[0000:irq4];   { Save the segment and }
  420.                   oldvecseg:=memw[0000:irq4+2]; { offset of the DOS    }
  421.                                                 { interrupt handler    }
  422.                   registers.ax:=registers.ax+$0c;
  423.                                              { Use the COM1: interrupt }
  424.                   intr($21,registers);          { Call DOS to reset    }
  425.  
  426.  
  427.                   port[$21]:=tbyte and $ef;     { INT 0C               }
  428.                 end;
  429.           com2: begin
  430.                   oldvecoff:=memw[0000:irq3];   { Same as above        }
  431.                   oldvecseg:=memw[0000:irq3+2]; { Same as above        }
  432.                   registers.ax:=registers.ax+$0b;
  433.                                              { Use the COM2: interrupt }
  434.                   intr($21,registers);          { Call DOS             }
  435.                   port[$21]:=tbyte and $f7;     {                      }
  436.                 end;
  437.         end;
  438.         inline($fb);                            { Enable interrupts    }
  439.       END;
  440.  
  441.   {---------------------------------------------------------------------
  442.   This procedure restores the original system values to what they were before
  443.   the interrupt handler was set into action.
  444.   ---------------------------------------------------------------------}
  445.  
  446.     PROCEDURE IntOff;
  447.  
  448.       VAR
  449.         tbyte:byte;
  450.  
  451.       BEGIN
  452.         inline($FA);  { CLI }                 { Disable interrupts     }
  453.         tbyte:=port[$21];                     {                        }
  454.         port[comport+intenreg]:=0;            { Disable COM interrupts }
  455.         If comport=$3f8 then                  { If using COM1: then    }
  456.           begin
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  472.   VERSION : All
  473.        OS : PC-DOS, MS-DOS
  474.      DATE : August 1, 1986                              PAGE : 8/10
  475.     TITLE : INTERRUPT HANDLER
  476.  
  477.  
  478.  
  479.  
  480.             port[$21]:=tbyte or $10;          {                        }
  481.             memw[0000:irq4]:=oldvecoff;       { Restore the DOS        }
  482.             memw[0000:irq4+2]:=oldvecseg;     { interrupt handler      }
  483.           end
  484.         else
  485.           begin
  486.             memw[0000:irq3]:=oldvecoff;         { Restore the DOS   }
  487.             memw[0000:irq3+2]:=oldvecseg;       { interrupt handler }
  488.             port[$21]:=tbyte or $08;            {                   }
  489.           end;e
  490.       END;
  491.   {------------------------------------------------------------------
  492.   If the ring buffer indexes are not equal then ReadCom returns the char from
  493.   either the COM1: or COM2: port. The character is read from the ring buffer
  494.   and is stored in the FUNCTION result.
  495.   -------------------------------------------------------------------}
  496.  
  497.     FUNCTION ReadCom : char;
  498.  
  499.       BEGIN
  500.         If ( head <> tail ) then           { Check for ring buffer  }
  501.           begin                            { character              }
  502.             If ( tail < buffsize ) then    { Check the limits of    }
  503.               tail := tail + 1             { the ring and set tail  }
  504.             else                           { accordingly            }
  505.               tail := 0;
  506.             ReadCom := intbuffer[tail].c;  { Get the character      }
  507.           end;
  508.       END;
  509.  
  510.   {------------------------------------------------------------------
  511.   This procedure outputs directly to the communications port the byte
  512.   equivilent of the character to be sent.
  513.   ------------------------------------------------------------------}
  514.  
  515.     PROCEDURE WriteCom( ch : char );
  516.  
  517.       VAR
  518.         tbyte:byte;
  519.  
  520.       BEGIN
  521.         tbyte:=ord(ch);                { Change to byte format      }
  522.         port[comport]:=tbyte;          { Output the character       }
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  538.   VERSION : All
  539.        OS : PC-DOS, MS-DOS
  540.      DATE : August 1, 1986                              PAGE : 9/10
  541.     TITLE : INTERRUPT HANDLER
  542.  
  543.  
  544.  
  545.  
  546.       END;
  547.   {------------------------------------------------------------------
  548.   When the interrupt routine is called because of a com port interrupt the
  549.   head index is incremented by one, but does not increment the tail index.
  550.   This causes the two indexes to be unequal, and ModemInput to become true.
  551.   ------------------------------------------------------------------}
  552.  
  553.   FUNCTION ModemInput:boolean;
  554.  
  555.     begin
  556.       ModemInput:=(head<>tail);
  557.       end;
  558.  
  559.   BEGIN
  560.     segment := dseg;         { segment is an absolute variable used  }
  561.                              { by the interrupt routine to restore   }
  562.                              { the DS register to point to the DSEG  }
  563.     AskCom( comp );          { Get the com port to use               }
  564.     IntOn( comp );           { Set up the interrupt routine          }
  565.  
  566.     ch:=' ';                 { Initialize ch for the loop            }
  567.     Repeat
  568.       If keypressed then     { If a key is pressed on the keyboard   }
  569.         begin
  570.           read(kbd,kch);     { then the program reads it in and      }
  571.           kch := Upcase(kch);
  572.           write( kch );
  573.           If ( kch = chr(13)) then writeln;
  574.                              { checks if the program should be ended }
  575.           WriteCom(kch);     { Write the character to the com port   }
  576.         end;
  577.       If ModemInput then     { If something was placed in the ring   }
  578.         begin                { buffer then                           }
  579.           write('[');
  580.           ch:=ReadCom;       { it is read in and printed to the      }
  581.           write(ch);         { screen                                }
  582.           If ch=chr(13) then writeln;
  583.           write(']');
  584.         end;
  585.     Until kch=chr(27);       { This loops ends when <esc> is hit     }
  586.     IntOff;                  { Restore the environment               }
  587.   END.        { Main program }
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.   PRODUCT : TURBO PASCAL                               NUMBER : 152
  604.   VERSION : All
  605.        OS : PC-DOS, MS-DOS
  606.      DATE : August 1, 1986                             PAGE : 10/10
  607.     TITLE : INTERRUPT HANDLER
  608.  
  609.  
  610.  
  611.  
  612.   DISCLAIMER: You have the right to use this technical information subject to
  613.   the terms of the No-Nonsense License Statement that you received with the
  614.   Borland product to which this information pertains.
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.